package cn.anecansaitin.whimsy.common.entity.ow;

import cn.anecansaitin.whimsy.common.capabilities.battle.DoomfistBattle;
import cn.anecansaitin.whimsy.common.capabilities.battle.IBattleMode;
import cn.anecansaitin.whimsy.common.extension.obb.OBB;
import cn.anecansaitin.whimsy.common.register.ModDamageSources;
import cn.anecansaitin.whimsy.common.register.ModEffects;
import cn.anecansaitin.whimsy.common.register.ModEntities;
import it.unimi.dsi.fastutil.floats.FloatConsumer;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.joml.Math;
import org.joml.Quaternionf;
import org.joml.Vector3f;

import java.util.HashSet;
import java.util.List;
import java.util.function.IntConsumer;

public class SeismicSlamWave extends Projectile {
    private final Vec3 movement;
    private final OBB hitBox;
    /**
     * 已经被攻击过的实体，不要再次对其造成伤害
     */
    private final HashSet<Entity> hitEntities;
    private IntConsumer shieldGenerater;
    private FloatConsumer ultimateCharger;

    public SeismicSlamWave(EntityType<? extends Projectile> pEntityType, Level pLevel) {
        super(pEntityType, pLevel);
        movement = new Vec3(0, 0, 0);
        setDeltaMovement(movement);
        hitBox = OBB.EMPTY;
        hitEntities = new HashSet<>();
        setMaxUpStep(1);
    }

    /**
     * @param yRot           y轴旋转角度，一般为发射实体的yRot
     * @param x              x坐标
     * @param y              y坐标
     * @param z              z坐标
     * @param entityMarker   攻击过的实体集合，避免重复攻击，多个波需要共享同一个集合
     * @param ultimateCharger
     */
    public SeismicSlamWave(float yRot, double x, double y, double z, HashSet<Entity> entityMarker, Entity owner, IntConsumer shieldGenerater, FloatConsumer ultimateCharger) {
        super(ModEntities.SEISMIC_SLAM_WAVE.get(), owner.level());
        movement = calculateViewVector(0, yRot).scale(2);//todo 目标是1秒钟20格
        setPos(x, y, z);
        setDeltaMovement(movement);
        setYRot(-yRot);
        hitBox = new OBB(new Vector3f((float) x, (float) y + 0.75f, (float) z), new Vector3f(0.5f, 0.75f, 0.25f), new Quaternionf(0, Math.toRadians(yRot), 0, 1));
        this.hitEntities = entityMarker;
        entityMarker.add(owner);
        setOwner(owner);
        setMaxUpStep(1);
        this.shieldGenerater = shieldGenerater;
        this.ultimateCharger = ultimateCharger;
    }

    @Override
    public void setDeltaMovement(Vec3 pDeltaMovement) {
        super.setDeltaMovement(pDeltaMovement);
    }

    @Override
    public Packet<ClientGamePacketListener> getAddEntityPacket() {
        return super.getAddEntityPacket();
    }

    @Override
    public void tick() {
        if (level().isClientSide) {
            super.tick();
            move(MoverType.SELF, getDeltaMovement());
            return;
        }

        //伤害判定
        List<Entity> entities = level().getEntities((Entity) null, new AABB(getX() - 1, getY(), getZ() - 1, getX() + 1, getY() + 2, getZ() + 1), entity -> entity != this && !hitEntities.contains(entity));
        int count = 0;

        for (Entity entity : entities) {
            if (!hitBox.isCollision(entity)) {
                continue;
            }

            count++;
            hitEntities.add(entity);
            entity.hurt(ModDamageSources.owNoKnockback(level(), this, getOwner(), this.position()), 5);

            if (entity instanceof LivingEntity living) {
                //30%的减速，持续3秒
                living.addEffect(new MobEffectInstance(ModEffects.SLOWDOWN.get(), 20 * 3, 29));
            }
        }

        if (count > 0) {
            //触发最佳防守
            generateShield(count);
            //为大招充能
            chargeUltimate(count * 5);
        }

        super.tick();
        move(MoverType.SELF, getDeltaMovement());

        //最长存在时间
        if (tickCount > 10 || fallDistance > 1) {
            remove(RemovalReason.DISCARDED);
        } else {
            setDeltaMovement(movement.x, -5, movement.z);
            //移动伤害判定盒
            //todo 把z范围扩大，目前想法是通过在xz方向的移动速度来计算
            hitBox.halfExtents().set(0.5f, 0.5f, 0.25f + 0.5f);
            hitBox.center().set(getX(), getY() + 0.75f, getZ());
            hitBox.move(-0.5f);
        }

        hasImpulse = true;
    }

    /**
     * 这个方法与父类方法基本一致，仅在上台阶失败后直接移除实体<br>
     * 该方法在Entity中为private，需要通过AT拓宽访问权限
     */
    @Override
    protected Vec3 collide(Vec3 pVec) {
        AABB aabb = this.getBoundingBox();
        List<VoxelShape> list = this.level().getEntityCollisions(this, aabb.expandTowards(pVec));
        Vec3 vec3 = pVec.lengthSqr() == 0.0 ? pVec : collideBoundingBox(this, pVec, aabb, this.level(), list);
        boolean flag = pVec.x != vec3.x;
        boolean flag1 = pVec.y != vec3.y;
        boolean flag2 = pVec.z != vec3.z;
        boolean flag3 = this.onGround() || flag1 && pVec.y < 0.0;
        float stepHeight = getStepHeight();
        if (stepHeight > 0.0F && flag3 && (flag || flag2)) {
            Vec3 vec31 = collideBoundingBox(this, new Vec3(pVec.x, (double) stepHeight, pVec.z), aabb, this.level(), list);
            Vec3 vec32 = collideBoundingBox(
                    this, new Vec3(0.0D, (double) stepHeight, 0.0D), aabb.expandTowards(pVec.x, 0.0D, pVec.z), this.level(), list
            );
            if (vec32.y < (double) stepHeight) {
                Vec3 vec33 = collideBoundingBox(this, new Vec3(pVec.x, 0.0, pVec.z), aabb.move(vec32), this.level(), list).add(vec32);
                if (vec33.horizontalDistanceSqr() > vec31.horizontalDistanceSqr()) {
                    vec31 = vec33;
                }
            }

            if (vec31.horizontalDistanceSqr() > vec3.horizontalDistanceSqr()) {
                return vec31.add(collideBoundingBox(this, new Vec3(0.0, -vec31.y + pVec.y, 0.0), aabb.move(vec31), this.level(), list));
            } else {
                //当没能成功上台阶，则移除实体
                remove(RemovalReason.DISCARDED);
            }
        }

        return vec3;
    }

    @Override
    protected void defineSynchedData() {

    }

    private void generateShield(int count) {
        if (shieldGenerater == null) {
            Entity owner = getOwner();

            if (owner == null) {
                return;
            }

            IBattleMode battleMode = owner.getCapability(IBattleMode.BATTLE_MODE);

            if (battleMode == null) {
                return;
            }

            if (!(battleMode.getController() instanceof DoomfistBattle doomfist)) {
                return;
            }

            this.shieldGenerater = doomfist.generateShield;
        } else {
            shieldGenerater.accept(count);
        }
    }

    private void chargeUltimate(float damage) {
        if (ultimateCharger == null) {
            Entity owner = getOwner();

            if (owner == null) {
                return;
            }

            IBattleMode battleMode = owner.getCapability(IBattleMode.BATTLE_MODE);

            if (battleMode == null) {
                return;
            }

            if (!(battleMode.getController() instanceof DoomfistBattle doomfist)) {
                return;
            }

            this.ultimateCharger = doomfist.ultimateCharger;
        } else {
            ultimateCharger.accept(damage);
        }
    }
}
